查看原文
其他

Android深入理解包管理---apk信息

牛晓伟 牛晓伟
2024-12-14

戳蓝字“牛晓伟”关注我哦!

用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章,技术文章也可以有温度。

前言

阅读该篇之前,建议先阅读下面的系列文章:

Android深入理解包管理--PackageManagerService和它的“小伙伴”

Android深入理解包管理--记录存储模块

Android深入理解包管理--共享库模块

本文摘要

这是包管理系列的第四篇文章,apk信息指的是AndroidManifest.xml文件中配置的各种信息,通过本文您将了解到apk信息为啥如此重要apk信息的解析apk信息最终被存放在哪。(文中代码基于Android13)

本文大纲

1. apk信息如此重要

2. apk信息的解析

3. apk信息的一生

4. 总结

1. apk信息如此重要

首先apk信息指的是AndroidManifest.xml文件中配置的各种信息,比如apk版本信息apk包名声明了哪些四大组件使用了哪些权限声明了哪些权限使用了哪些共享库等。

本篇内容为啥要介绍apk信息呢?

首要的原因是因为apk信息对于PackageManagerService服务来说非常的重要,PackageManagerService管理的对象是apk,而要想知道apk内包含了哪些内容是不是需要从AndroidManifest.xml文件中获取到apk信息,只有获取到apk信息才能对apk进行管理。

其次是PackageManagerService很多的模块都是为apk信息服务的,比如共享库模块是为apk声明共享库 (在AndroidManifest.xml文件中使用library标签)和使用共享库 (在AndroidManifest.xml文件中使用uses-library标签)信息服务的,权限管理模块是为apk声明权限 (在AndroidManifest.xml文件中使用permission标签)和使用权限 (在AndroidManifest.xml文件中使用uses-permission标签)信息服务的。

说了这么多apk信息的重要性,那我们来看下apk信息是如何解析的吧?

2. apk信息的解析

PackageManagerService要想知道apk信息,就得需要从apk的AndroidManifest.xml文件中把这些信息解析为对应的标签数据类,那就来介绍下这些数据类吧。介绍数据类时秉持从小到大的原则来介绍,啥叫从小到大呢,也就是先把AndroidManifest.xml文件中的常用小标签对应的数据类开始,逐步在来介绍更大一些的标签对应的数据类,那先从四大组件开始。

2.1 四大组件对应的标签数据类

大家都知道四大组件对应的标签是activityreceiverserviceprovider,下图展示了它们的类图关系

图解

ParsedComponent

很多的标签都存在一些共同的配置信息,如下代码activitypermission标签都存在android:iconandroid:banner配置信息,而ParsedComponent接口的作用就是把多个标签共有的配置信息收集起来,提供统一的方法

<activity  android:icon="" android:banner="">
<permission  android:icon=""  android:banner=""/>

ParsedComponentImpl

该类从名字上看就知道它是实现了ParsedComponent接口

ParsedMainComponentImpl

上图没有体现出来,该类实现了ParsedMainComponent接口,而该接口的作用是把四大组件的标签共有的配置信息收集起来,提供统一的方法,如下代码展示了一些共有的配置信息

<provider android:name="" android:process="" android:enabled="" android:exported=""/>
<service android:name="" android:process="" android:enabled="" android:exported=""/>
<receiver android:name="" android:process="" android:enabled="" android:exported=""/>
<activity android:name="" android:exported="" android:enabled=""  android:process="">

ParsedActivityImpl

activityreceiver这两个标签会被解析为ParsedActivityImpl类,标签中配置的数据自然而然的就存放在该类中,如android:launchMode配置的信息存放在该类的launchMode属性中。

下图是ParsedActivityImpl的继承关系

ParsedActivity是一个接口,它定义了activityreceiver标签独有的接口,而ParsedActivityImpl类实现了ParsedActivity接口同时也继承了ParsedMainComponentImpl

ParsedServiceImpl

service标签会被解析为该类,而该类也继承了ParsedMainComponentImpl类,并且它也实现了自己的接口ParsedService

ParsedProviderImpl

provider标签会被解析为该类,它同样也继承了ParsedMainComponentImpl类,并且它也实现了自己的接口ParsedProvider

2.2 权限相关的标签数据类

安装在Android设备上的app基本都会使用到各式各样的权限,权限也属于常用到的标签,故介绍下它们。权限分为声明权限使用权限

声明权限也就是app可以在AndroidManifest.xml中通过permission标签来声明权限,如下代码:

<permission android:description="string resource"
            android:icon="drawable resource"
            android:label="string resource"
            android:name="string"
            android:permissionGroup="string"
            android:protectionLevel=["normal" | "dangerous" |
                                     "signature" | ...] />

而使用权限就是在AndroidManifest.xml中通过uses-permission标签来使用权限,如下代码:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

下面是权限标签对应的类图

图解

ParsedPermissionImpl

permission标签会被解析为该类,它实现了ParsedPermission接口

ParsedUsesPermissionImpl

uses-permission标签会被解析为该类,它实现了ParsedUsesPermission接口

因为AndroidManifest中的标签很多,只把常用的介绍完就够用了,如果大家想了解其他的标签可以遵循如下的原则:

  1. 标签数据类的命名格式是ParsedXXXXImpl (如ParsedActivityImpl)
  2. 每个标签数据类都有自己对应的接口,接口命名格式为ParsedXXXX (如ParsedActivity),即使像ParsedUsesPermissionImpl这么简单的类它都有自己的接口ParsedUsesPermission
  3. ParsedComponentImpl类收集了大部分标签共用的信息,而它的接口是ParsedComponent
  4. ParsedMainComponentImpl类收集了四大组件标签共用的信息,而它的接口是ParsedMainComponent

2.3 AndroidManifest对应的数据类

AndroidManifest内有各种标签,基本每个标签都会有自己的标签数据类 (除了application、manifest标签),在AndroidManifest中每个标签都会被包含于某个大标签内 (如 application被包含于 manifest标签),同样也会有一个最终的标签数据类把所有的标签数据类都包含进来,这个类就是PackageImpl,如下是它的类图:

图解

PackageImpl

AndroidManifest中的信息会对应一个PackageImpl实例,它实现了ParsedPackageAndroidPackage接口,并且它继承了ParsingPackageImpl类,大部分逻辑可都是集中在ParsingPackageImpl类中

ParsingPackageImpl

如上图,它的很多属性,如下:

  1. activities它包含了很多的ParsedActivity
  2. receivers它包含了很多的ParsedActivity
  3. services它包含了很多的ParsedService
  4. attributions它包含了很多的ParsedAttribution
  5. permissions它包含了很多的ParsedPermission

ParsingPackageImpl类的属性包含的都是各标签数据类的接口,这就是所谓的面向接口编程,好处就是该类基本不需要改动,比如ParseActivity又增加了一个子类,那在往ParsingPackageImpl中添加该子类的时候就不需要改动ParsingPackageImpl里的代码了。

applicationmanifest标签并没有对应的标签数据类,它们配置的信息也是放在ParsingPackageImpl类中的,比如application标签中配置的android:name信息,它是存放在ParsingPackageImpl的类型为StringclassName属性中的。

2.4 小结

  1. 四大组件对应的数据类分别是ParsedActivityImplParsedServiceImplParsedProviderImpl

  2. 权限相关的标签permissionuses-permission对应的数据类是ParsedPermissionImplParsedUsesPermissionImpl

  3. AndroidManifest会对应一个PackageImpl实例,而它的父类ParsingPackageImpl存放了所有的数据类。

标签数据类有一个规则:每个类的命名规则是ParsedXXXXImpl (XXXX 代表对应的标签),每个类都有对应的接口命名规则是ParsedXXXX

3. apk信息的一生

apk信息的诞生apk信息的归属地apk信息的消亡来介绍apk信息在PackageManagerService服务中的一生。

3.1 apk信息的诞生

apk信息的诞生时机主要是在apk安装apk升级Android设备启动时扫描所有apk三种情况,不管哪种情况首要做的最重要的工作是从apk的AndroidManifest.xml文件中把配置信息解析出来,配置信息解析出来就代表apk信息诞生了。

无论是apk安装apk升级扫描所有apk或多或少都会使用apk信息来进行各种验证,比如apk完整性验证、apk版本验证 (如果存在老apk)、新老apk签名验证 (如果存在老apk),经过各种步骤后,apk顺利的安装完成了,而apk信息也需要找一个归属地来存储它们。

3.2 apk信息的归属地

apk信息的归属地代表需要在PackageManagerService中把apk信息保存起来,如下代码:

//PackageManagerService类

//mPackages存储了所有的apk信息,key值为包名,value为apk信息
final WatchedArrayMap<String, AndroidPackage> mPackages = new WatchedArrayMap<>();

而apk信息中的四大组件,则是存放在四大组件模块,如下代码:

//PackageManagerService类

//mComponentResolver存储了四大组件
final ComponentResolver mComponentResolver;

apk信息保存下来后就可以被使用了,比如启动该apk的某个ActivityActivityTaskManagerService就需要从四大组件模块中查询到相应的Activity信息,进而才执行后面的启动操作。再比如某个App获取该apk的ApplicationInfo信息,则会从PackageManagerServicemPackages属性中根据包名找到对应的apk信息,进而返回。

3.3 apk信息的消亡

apk被卸载或者systemserver进程死掉的话,PackageManagerService四大组件模块中保存的apk信息会被移除,代表apk信息消亡了。如果不存在上面的情况,则apk信息会随着PackageManagerService一直存活着。

4. 总结

本文介绍了apk信息在PackageManagerService服务中的重要性,以及apk信息的解析和apk信息在PackageManagerService中的一生。


欢迎关注我的公众号,里面有更多精彩内容等着大家


继续滑动看下一个
牛晓伟
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存